﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LitJson;
using UnityEngine;


public class ItemManager
{
    public string ConfigPath;
    public string WeaponConfigPath;
    public static ItemManager Instance = new ItemManager();
    List<ItemObjectBase> m_ItemObjs = new List<ItemObjectBase>();

    public List<Item> m_Items       = new List<Item>();
    public List<Weapon> m_Weapons   = new List<Weapon>();
    public List<Part> m_Parts       = new List<Part>();
    public List<Material> m_Materials   = new List<Material>();

    public List<Item> m_Batteries   = new List<Item>();
    public List<Item> m_Dynamos     = new List<Item>();
    public List<Item> m_Engines     = new List<Item>();
    public List<Item> m_Hook        = new List<Item>();
    public List<Item> m_Shall       = new List<Item>();
    public List<Item> m_Shild       = new List<Item>();
    public List<Item> m_WeaponSlots = new List<Item>();
    public List<Item> m_Ores        = new List<Item>();
    public List<Item> m_OtherParts  = new List<Item>();

    public List<Item> m_Artillary   = new List<Item>();
    public List<Item> m_Laser       = new List<Item>();
    public List<Item> m_RailGun     = new List<Item>();
    public List<Item> m_Rocket      = new List<Item>();

    public Dictionary<Item.ItemType, int> m_ItemTypeIDCounter = new Dictionary<Item.ItemType, int>();

    private ItemManager()
    {
        ConfigPath = Utils.GetDataPath() + "ItemsList.data";
        WeaponConfigPath = Utils.GetDataPath() + "WeaponsList.data";
    }

    public void InitSystem()
    {
        // Parts
        register<Battery>();
        register<Dynamo>();
        register<Engine>();
        register<Hook>();
        register<Part>();
        register<Shall>();
        register<Shild>();
        register<WeaponSlot>();
        register<Other>();

        // Weapons
        register<Artillery>();
        register<Laser>();
        register<Railgun>();
        register<Rocket>();

        // Materials
        register<Ore>();

        //  Load Items
        var jsonData = Utils.LoadJson(ConfigPath);
        Load(jsonData);

        //  Load Weapons
        jsonData = Utils.LoadJson(WeaponConfigPath);
        Load(jsonData); 
    }



    public void Load(JsonData json)
    {
        if (json == null)
        {
            MessageShow.Instance.Error("we can't load the json of item's because the json is null");
            return;
        }
        IDictionary<string, JsonData> jsond = json.ValueAsObject();
        /// Global
        //if (jsond.ContainsKey("DelvelopmentMode"))
        //    m_DevelopmentMode = jsond["DelvelopmentMode"].ValueAsBoolean();

        
        // Parts
        if (jsond.ContainsKey("Parts"))
        {
            var jsonParts = jsond["Parts"].ValueAsObject();
            foreach (var i in Enum.GetValues(typeof(Item.ItemType)))
            {
                var itemType = (Item.ItemType)i;
                string key = itemType.ToString();
                if (jsonParts.ContainsKey(key))
                {
                    var jsonPartSub = jsonParts[key];
                    for (int j = 0; j < jsonPartSub.Count; ++j)
                    {
                        var item = Item.CreateItemPrefab(jsonPartSub[j], itemType);
                        item.m_Type = itemType;
                        item.typeID = ((int)item.m_Type)  + j;
                        AddToList(item);
                    }
                }
            }
        }

        // Weapon
        if (jsond.ContainsKey("Weapons"))
        {
            var jsonWeapons = jsond["Weapons"].ValueAsObject();
            foreach(var i in Enum.GetValues(typeof(Item.ItemType)))
            {
                var itemType = (Item.ItemType)i;
                string key = itemType.ToString();
                if (jsonWeapons.ContainsKey(key))
                {
                    var jsonWeaponSub = jsonWeapons[key];
                    for (int j = 0; j < jsonWeaponSub.Count; ++j)
                    {
                        var item = Item.CreateItemPrefab(jsonWeaponSub[j], itemType);
                        item.m_Type = itemType;
                        //Debug.Log("the weapon's ID is " + ((int)itemType)+"--- after translate is "+ (int)item.m_Type);
                        item.typeID = ((int)item.m_Type) + j;
                        AddWeapon(item as Weapon);
                    } 
                }
            }
        }
    }
    public void RemoveWeapon(Weapon weapon)
    {
        if (weapon == null)
        {
            MessageShow.Instance.Error("移除武器从系统失败");
            return;
        }
        m_Items.Remove(weapon);
        m_Weapons.Remove(weapon);

        m_Artillary.Remove(weapon);
        m_Laser    .Remove(weapon);
        m_RailGun  .Remove(weapon);
        m_Rocket   .Remove(weapon);
    }
    public void AddWeapon(Weapon weapon)
    {
        if(weapon == null)
        {
            MessageShow.Instance.Error("添加武器到系统失败");
            return;
        }

        // 如果存在则覆盖
        if(weapon.typeID != 0)
        {
            Item e = FindItem(weapon.typeID);
            if (e != null)
            {
                e.Copy(weapon);
                return;
            }
        }


        if (m_ItemTypeIDCounter.ContainsKey(weapon.m_Type))
        {
            if (weapon.typeID == 0)
            {
                weapon.typeID = m_ItemTypeIDCounter[weapon.m_Type] + 1;
                m_ItemTypeIDCounter[weapon.m_Type] = weapon.typeID;
            }
            else
            {
                if (weapon.typeID > m_ItemTypeIDCounter[weapon.m_Type])
                    m_ItemTypeIDCounter[weapon.m_Type] = weapon.typeID;
            }
        }
        else
        {
            if(weapon.typeID != 0)
            {
                m_ItemTypeIDCounter.Add(weapon.m_Type, weapon.typeID);
            }
            else
            {
                weapon.typeID = (int)weapon.m_Type;
                m_ItemTypeIDCounter.Add(weapon.m_Type, weapon.typeID);
            }
        }

        AddToList(weapon);
    }
    public int GetItemTypeIDCount(Item.ItemType itemType)
    {
        if (m_ItemTypeIDCounter.ContainsKey(itemType))
        {
            return m_ItemTypeIDCounter[itemType];
        }
        return -1;
    }
    public void SetItemTypeIDCount(Item.ItemType itemType, int count)
    {
        if (m_ItemTypeIDCounter.ContainsKey(itemType))
        {
            m_ItemTypeIDCounter[itemType] = count;
        }
    }
    void AddToList(Item item)
    {
        m_Items.Add(item);
        switch(item.m_Type)
        {
            case Item.ItemType.ENGINE:
                m_Engines.Add(item);
                m_Parts.Add(item as Part);
                break;
            case Item.ItemType.BATTERY:
                m_Batteries.Add(item);
                m_Parts.Add(item as Part);
                break;
            case Item.ItemType.DYNAMO:
                m_Dynamos.Add(item);
                m_Parts.Add(item as Part);
                break;
            case Item.ItemType.HOOK:
                m_Hook.Add(item);
                m_Parts.Add(item as Part);
                break;
            case Item.ItemType.SHALL:
                m_Shall.Add(item);
                m_Parts.Add(item as Part);
                break;
            case Item.ItemType.WEAPON_SLOT:
                m_WeaponSlots.Add(item);
                m_Parts.Add(item as Part);
                break;
            case Item.ItemType.OTHER_PART:
                m_OtherParts.Add(item);
                m_Parts.Add(item as Part);
                break;
            case Item.ItemType.ARTILLARY:
                m_Artillary.Add(item);
                m_Weapons.Add(item as Weapon);
                break;
            case Item.ItemType.LASER:
                m_Laser.Add(item);
                m_Weapons.Add(item as Weapon);
                break;
            case Item.ItemType.RAILGUN:
                m_RailGun.Add(item);
                m_Weapons.Add(item as Weapon); 
                break;
            case Item.ItemType.ROCKET:
                m_Rocket.Add(item);
                m_Weapons.Add(item as Weapon);
                break;
            case Item.ItemType.ORE:
                m_Ores.Add(item);
                m_Materials.Add(item as Material);
                break;
        }
    }


    public void register<T>() where T : new()
    {
        m_ItemObjs.Add(new ItemObject<T>());
    }

    public Item FindItem(Item.ItemType type)
    {
        foreach(var i in m_Items)
        {
            if(i.m_Type == type)
            {
                return i;
            }
        }
        return null;
    }
    public Item FindItem(int typeID)
    {
        foreach (var i in m_Items)
        {
            if (i.typeID == typeID)
            {
                return i;
            }
        }
        return null;
    }

    public Item createItem(string itemName)
    {
        for (int i = 0; i < m_ItemObjs.Count; ++i)
        {
            if (m_ItemObjs[i].m_Name == itemName)
            {
                var newItem = m_ItemObjs[i].createItem();
                var oldItem = FindItem(m_ItemObjs[i].m_Item.m_Type);
                if (oldItem != null)
                    newItem.Copy(oldItem);
                return newItem;
            }
        }
        return null;
    }
    public Item createItem(Item oldItem)
    {
        for (int i = 0; i < m_ItemObjs.Count; ++i)
        {
            if (m_ItemObjs[i].m_Name == oldItem.m_Type.ToString())
            {
                var newItem = m_ItemObjs[i].createItem();
                newItem.Copy(oldItem);
                return newItem;
            }
        }
        return null;
    }
    public Item createItem(int typeID)
    {
        for (int i = 0; i < m_Items.Count; ++i)
        {
            if (m_Items[i].typeID == typeID)
            {
                var newItem = createItem(m_Items[i].m_Type.ToString());
                newItem.Copy(m_Items[i]);
                return newItem;
            }
        }
        return null;
    }
    
    public void SaveWeapons()
    {
        JsonData root = new JsonData();
        JsonData weaponsObj = new JsonData();
        weaponsObj.SetJsonType(JsonType.Object);


        Func<List<Item>, JsonData> x = (List<Item> weaponList)=>
        {
            JsonData weaponJson = new JsonData();
            weaponJson.SetJsonType(JsonType.Array);
            for (int i = 0; i < weaponList.Count; ++i)
            {
                JsonData weaponJ = new JsonData();
                weaponList[i].SavePrefab(weaponJ);
                weaponJson.Add(weaponJ);
            }
            return weaponJson;
        };

        weaponsObj[Item.ItemType.ARTILLARY.ToString()] = x.Invoke(m_Artillary);
        weaponsObj[Item.ItemType.LASER.ToString()] = x.Invoke(m_Laser);
        weaponsObj[Item.ItemType.RAILGUN.ToString()] = x.Invoke(m_RailGun);
        weaponsObj[Item.ItemType.ROCKET.ToString()] = x.Invoke(m_Rocket);

        root["Weapons"] = weaponsObj;


        string data = root.ToJson();
        using (FileStream fs = new FileStream(WeaponConfigPath, FileMode.Create, FileAccess.Write))
        {
            byte[] array = System.Text.Encoding.UTF8.GetBytes(data);
            fs.Write(array, 0, (int)array.Length);
            fs.Close();
        }
    }
}

public class ItemObjectBase
{
    public Item m_Item;
    public string m_Name;
    virtual public Item createItem()
    {
        return null;
    }
}

public class ItemObject<T> : ItemObjectBase where T : new()
{
    public ItemObject()
    {
        m_Item = new T() as Item;
        m_Name = m_Item.m_Type.ToString();
    }
    public override Item createItem()
    {
        var item = new T() as Item;
        item.typeID = ((int)item.m_Type) * Item.typeIDInCrement; ;
        return item;
    }
}